﻿/******************************************************
* author :  HZK
* email  :  icecoke-zk@live.com 
* history:  created by hzk 2015/8/16 23:22:49 
* clrversion :4.0.30319.18444
******************************************************/

using Machine.DataAccess.Linq;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Reflection;

using System.Data.SqlClient;
using Machine.DataAccess.Common.ORM;
using System.Linq;

namespace Machine.DataAccess.Operation.Mysql
{
    /// <summary>
    /// Mysql类的实现操作
    /// 单例模式
    /// </summary>
    class MysqlDataSchemCreator : DataSchemCreatorBase
    {
        //private static Lazy<MysqlDataSchemCreator> _instance = new Lazy<MysqlDataSchemCreator>(() =>
        //{
        //    return new MysqlDataSchemCreator();
        //}, true);

        //public static MysqlDataSchemCreator Instance { get { return _instance.Value; } }
        private static object _lock = new object();

        public MysqlDataSchemCreator(ProviderElement providerElement)
            : base(providerElement)
        {
        }

        /// <summary>
        /// 添加字段
        /// </summary>
        protected override string SQL_CreateBasic
        {
            get
            {
                return string.Format("ALTER TABLE {0} ADD {1} {2}", TABLEARG_NAME, COLUMARG_NAME, COLUMTYPEARG_NAME);
            }
        }

        /// <summary>
        /// 为对应的表格创建列
        /// </summary>
        /// <param name="table">表格名称</param>
        /// <param name="colum">创建的列信息</param>
        /// <returns></returns>
        public override bool CreateBaseType(Type table, PropertyInfo colum)
        {
            //var sql = this.SQL_CreateBasic;
            //DbParameter[] parameters = new DbParameter[3];
            //parameters[0] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();
            //parameters[1] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();
            //parameters[2] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();

            //parameters[0].ParameterName = TABLEARG_NAME;
            //parameters[0].Value = table.GetTableName();

            //parameters[1].ParameterName = COLUMARG_NAME;
            //parameters[1].Value = colum.Name;

            //parameters[2].ParameterName = COLUMTYPEARG_NAME;
            //parameters[2].Value = colum.PropertyType;

            //return DataResult.CodeFirstExcuteNonQuery(new TranslateResult(sql, parameters), this.ProviderElement);

            var strTemp = SQL_CreateBasic.Replace(TABLEARG_NAME, table.GetTableName())
                .Replace(COLUMARG_NAME, colum.Name)
                .Replace(COLUMTYPEARG_NAME, this.GetDbType(colum.PropertyType));

            return DataResult.CodeFirstExcuteNonQuery(new TranslateResult(strTemp, new DbParameter[0]), this.ProviderElement);
        }

        /// <summary>
        /// 添加外键关系
        /// </summary>
        protected override string SQL_CreateRelation
        {
            get
            {
                //alter table 外表名 add constraint 外键约束名称 foreign key(你的外键字段名) REFERENCES 主表表名(对应的表的主键字段名);
                return string.Format("ALTER TABLE {0} ADD {1} {4};ALTER TABLE {0} ADD CONSTRAINT FK_{5} FOREIGN KEY ({1}) REFERENCES {2} ({3}) ON DELETE CASCADE", TABLEARG_NAME, COLUMARG_NAME, OUTTERTABLE_NAME, OUTTERKEY_NAME, COLUMTYPEARG_NAME, Guid.NewGuid().ToString().Replace("-", ""));
            }
        }
        /// <summary>
        /// 创建关联的外键关系
        /// </summary>
        /// <param name="tableName">从表格名称</param>
        /// <param name="columName">外键名称</param>
        /// <param name="columType">外键类型</param>
        /// <param name="outterTable">主表格名称</param>
        /// <param name="outterKey">主键名称</param>
        /// <returns></returns>
        public override bool CreateFK(string tableName, string columName, string columType, string outterTable, string outterKey)
        {
            //var sql = this.SQL_CreateRelation;
            //DbParameter[] parameters = new DbParameter[4];
            //parameters[0] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();
            //parameters[1] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();
            //parameters[2] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();
            //parameters[3] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();

            //parameters[0].ParameterName = TABLEARG_NAME;
            //parameters[0].Value = tableName;

            //parameters[1].ParameterName = COLUMARG_NAME;
            //parameters[1].Value = columName;

            //parameters[2].ParameterName = OUTTERTABLE_NAME;
            //parameters[2].Value = outterTable;

            //parameters[2].ParameterName = OUTTERKEY_NAME;
            //parameters[2].Value = outterKey;

            //return DataResult.CodeFirstExcuteNonQuery(new TranslateResult(sql, parameters), this.ProviderElement);
            var strTemp = SQL_CreateRelation.Replace(TABLEARG_NAME, tableName)
                .Replace(COLUMARG_NAME, columName)
                .Replace(COLUMTYPEARG_NAME, columType)
                .Replace(OUTTERTABLE_NAME, outterTable)
                .Replace(OUTTERKEY_NAME, outterKey);
            return DataResult.CodeFirstExcuteNonQuery(new TranslateResult(strTemp, new DbParameter[0]), this.ProviderElement);
        }
        /// <summary>
        /// 创建表格
        /// </summary>
        /// <param name="type">创建表格数据类型</param>
        /// <returns></returns>
        //public override bool CreateTable(Type type)
        //{
        //    //判断是否存在
        //    var schem = Config.Instance.GetDbSchemInfo(this.ProviderElement);
        //    if (schem.ExtistTable(type.GetTableName())) return true;

        //    //根据对象创建表
        //    var primaryKeyInfos = this.GetTableInfos(type);
        //    foreach (var item in primaryKeyInfos)
        //    {
        //        this.CreateTable(item.Key.GetTableName(), item.Value.PropertyName, this.GetDbType(item.Value.PropertyInfo.PropertyType));
        //        var properties = DynamicAssignment.Instance.GetDictionary(item.Key);
        //        foreach (var property in properties)
        //        {
        //            if (property.Value == item.Value) continue;
        //            var typeCode = Type.GetTypeCode(property.Value.PropertyInfo.PropertyType);
        //            if (typeCode != TypeCode.Object || property.Value.PropertyInfo.PropertyType == typeof(Guid))
        //            {
        //                this.CreateBaseType(item.Key, property.Value.PropertyInfo);
        //            }
        //        }
        //    }

        //    //var relations = this.GetTableRelationType() 

        //    //关系创建
        //    var relations = this.GetRelationInfos(type);
        //    foreach (var item in relations)
        //    {
        //        switch (item.TableRelationType)
        //        {
        //            case TableRelationType.Zero2Zero:
        //                continue;
        //            case TableRelationType.Zero2One:
        //                this.CreateOneToOneRealtion(item.PKType, item.FKType);
        //                break;
        //            case TableRelationType.Zero2Many:
        //                this.CreateOneToOneRealtion(item.PKType, item.FKType);
        //                break;
        //            case TableRelationType.One2Zero:
        //                this.CreateOneToOneRealtion(item.FKType, item.PKType);
        //                break;
        //            case TableRelationType.One2One:
        //                this.CreateOneToOneRealtion(item.PKType, item.FKType);
        //                break;
        //            case TableRelationType.One2Many:
        //                this.CreateOneToOneRealtion(item.PKType, item.FKType);
        //                break;
        //            case TableRelationType.Many2Zero:
        //                this.CreateOneToOneRealtion(item.PKType, item.FKType);
        //                break;
        //            case TableRelationType.Many2One:
        //                this.CreateOneToOneRealtion(item.PKType, item.FKType);
        //                break;
        //            case TableRelationType.Many2Many:
        //                this.CreateManyToManyRealtion(item.PKType, item.FKType);
        //                break;
        //            default:
        //                break;
        //        }
        //    }
        //    //foreach (var item in relations)
        //    //{
        //    //    switch (item.RelationType)
        //    //    {
        //    //        case RelationType.One2One:
        //    //        case RelationType.One2Many:
        //    //            this.CreateOneToOneRealtion(item.PKType, item.FKType);
        //    //            break;
        //    //        case RelationType.Many2Many:
        //    //            this.CreateManyToManyRealtion(item.PKType, item.FKType);
        //    //            break;
        //    //        default:
        //    //            throw new NotSupportedException("不支持的关系类型");
        //    //    }
        //    //}
        //    return true;
        //}

        /// <summary>
        /// 创建Table 的SQL
        /// </summary>
        protected override string SQL_CreateTable
        {
            get
            {
                return string.Format("CREATE TABLE {0} ({1} {2} PRIMARY KEY auto_increment)", TABLEARG_NAME, COLUMARG_NAME, COLUMTYPEARG_NAME);
            }
        }
        /// <summary>
        /// 在数据库中创建包含主键的Table
        /// </summary>
        /// <param name="tableName">表格名称</param>
        /// <param name="primaryKeyName">主键名称</param>
        /// <param name="primaryKeyType">主键类型</param>
        /// <returns></returns>
        public override bool CreateTable(string tableName, string primaryKeyName, string primaryKeyType,bool isAutoKey = false)
        {
            //var sql = this.SQL_CreateTable;
            //DbParameter[] parameters = new DbParameter[3];
            //parameters[0] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();
            //parameters[1] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();
            //parameters[2] = DbProviderFactories.GetFactory(this.ProviderElement.Provider).CreateParameter();

            //parameters[0].ParameterName = TABLEARG_NAME;
            //parameters[0].Value = tableName;

            //parameters[1].ParameterName = COLUMARG_NAME;
            //parameters[1].Value = primaryKeyName;

            //parameters[2].ParameterName = COLUMTYPEARG_NAME;
            //parameters[2].Value = primaryKeyType;

            //return DataResult.CodeFirstExcuteNonQuery(new TranslateResult(sql, parameters.ToArray()), this.ProviderElement);

            var strTemp = SQL_CreateTable.Replace(TABLEARG_NAME, tableName)
                .Replace(COLUMARG_NAME, primaryKeyName)
                .Replace(COLUMTYPEARG_NAME, primaryKeyType);
            if (!isAutoKey) strTemp = strTemp.Replace("auto_increment", "");
            return DataResult.CodeFirstExcuteNonQuery(new TranslateResult(strTemp, new DbParameter[0]), this.ProviderElement);
        }



        /// <summary>
        /// 获取对象中的主键信息和对象类型信息
        ///     包括获取对象中IEnumerable类型和基础类型为object的主键信息
        ///     这些类型都将作为子表生成
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>

        /// <summary>
        /// 获取数据类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        protected override string GetDbType(Type type)
        {
            if (type == typeof(Guid)) return "char(36)";
            if (type == typeof(byte[])) return "blob";
            var code = Type.GetTypeCode(type);
            switch (code)
            {
                case TypeCode.Byte:
                case TypeCode.Boolean:
                    return "bit";
                case TypeCode.Decimal:
                    return "decimal(12,2)";
                case TypeCode.Int16:
                case TypeCode.UInt16:
                case TypeCode.SByte:
                    return "smallint";
                case TypeCode.Int32:
                case TypeCode.UInt32:
                    return "int";
                case TypeCode.Int64:
                case TypeCode.UInt64:
                    return "bigint";
                case TypeCode.Single:
                case TypeCode.Double:
                    return "double(12,2)";
                case TypeCode.DateTime:
                    return "datetime";
                case TypeCode.Char:
                    return "char(255)";
                case TypeCode.String:
                    return "text";
                default:
                    throw new NotSupportedException("Code first 异常类型");
            }
        }


        /// <summary>
        /// 获取关联关系
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        //private IEnumerable<RelationInfo> GetRelationInfos(Type type)
        //{
        //    var cache = new List<RelationInfo>();
        //    var hashSet = new HashSet<Type>();
        //    var stack = new Stack<Type>();
        //    stack.Push(type);
        //    while (stack.Count > 0)
        //    {
        //        var typeTemp = stack.Pop();
        //        if (hashSet.Contains(typeTemp)) continue;
        //        hashSet.Add(typeTemp);
        //        var properties = DynamicAssignment.Instance.GetDictionary(typeTemp);
        //        foreach (var property in properties)
        //        {
        //            var outterType = property.Value.PropertyInfo.PropertyType;
        //            var typeCode = Type.GetTypeCode(outterType);
        //            if (typeCode == TypeCode.Object && outterType != typeof(Guid))
        //            {
        //                if (outterType.IsGenericType && outterType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        //                {
        //                    outterType = outterType.GetGenericArguments()[0];
        //                    stack.Push(outterType);
        //                }
        //                else
        //                {
        //                    stack.Push(outterType);
        //                }
        //                var relationType = this.GetTableRelationType(typeTemp, outterType);
        //                var info = new RelationInfo() { PKType = typeTemp, FKType = outterType };
        //                info.TableRelationType = relationType;
        //                cache.Add(info);
        //                if (info.TableRelationType == TableRelationType.Many2Many) hashSet.Add(outterType);
        //                //if (outterType.IsGenericType && outterType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        //                //{
        //                    //outterType = outterType.GetGenericArguments()[0];
        //                    //stack.Push(outterType);
        //                    //var relation = DynamicAssignment.Instance.GetDictionary(outterType).FirstOrDefault(x => x.Value.PropertyInfo.PropertyType.IsGenericType
        //                    //    && x.Value.PropertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
        //                    //    && x.Value.PropertyInfo.PropertyType.GetGenericArguments()[0] == typeTemp);//查询IEnumerable
        //                    //var info = new RelationInfo() { PKType = typeTemp, FKType = outterType };
        //                    //info.RelationType = relation.Value == null ? RelationType.One2Many : RelationType.Many2Many;
        //                    //cache.Add(info);
        //                    //if (info.RelationType == RelationType.Many2Many) hashSet.Add(outterType);
                            
        //                //}
        //                //else
        //                //{
        //                //    stack.Push(outterType);
        //                //    cache.Add(new RelationInfo()
        //                //    {
        //                //        PKType = typeTemp,
        //                //        FKType = outterType,
        //                //        RelationType = RelationType.One2One
        //                //    });
        //                //}
        //            }
        //        }
        //    }
        //    return cache;
        //}

        /// <summary>
        /// 创建一对一的关联
        /// </summary>
        /// <param name="pkTable">主表类型</param>
        /// <param name="fkTable">从表类型</param>
        //protected override void CreateOneToOneRealtion(Type pkTable, Type fkTable)
        //{
        //    //var schem = Config.Instance.GetDbSchemInfo(this.ProviderElement);

        //    //var pkTableName = pkTable.GetTableName();
        //    //var pkTablePrimaryKey = schem.GetPrimaryKey(pkTableName);
        //    //var pkTablePrimaryKeyProperty = DynamicAssignment.Instance.GetDictionary(pkTable)[pkTablePrimaryKey].PropertyInfo;

        //    //var fkTableName = fkTable.GetTableName();
        //    //var fkTablePrimaryKey = schem.GetPrimaryKey(fkTableName);
        //    //var fkTablePrimaryKeyProperty = DynamicAssignment.Instance.GetDictionary(fkTable)[fkTablePrimaryKey].PropertyInfo;

        //    //this.CreateFK(fkTableName, fkTablePrimaryKey, this.GetDbType(fkTablePrimaryKeyProperty.PropertyType), pkTableName, pkTablePrimaryKey);

        //    var schem = Config.Instance.GetDbSchemInfo(this.ProviderElement);

        //    var tableName = pkTable.GetTableName();
        //    var tablePrimary = schem.GetPrimaryKey(tableName);
        //    var tablePrimaryProperty = DynamicAssignment.Instance.GetDictionary(pkTable)[tablePrimary].PropertyInfo;

        //    var outterTableName = fkTable.GetTableName();
        //    var outterPrimary = schem.GetPrimaryKey(outterTableName);
        //    var outterPrimaryProperty = DynamicAssignment.Instance.GetDictionary(fkTable)[outterPrimary].PropertyInfo;

        //    var tableNameTemp = string.Format("{0}_{1}_Relation", tableName, outterTableName);

        //    this.CreateFK(outterTableName, string.Format("{0}Relation", tableName), this.GetDbType(tablePrimaryProperty.PropertyType), tableName, tablePrimary);
        //}

        /// <summary>
        /// 创建多对多的关联
        /// </summary>
        /// <param name="table1">关联表一的类型</param>
        /// <param name="table2">关联表二的类型</param>
        //protected override void CreateManyToManyRealtion(Type table1, Type table2)
        //{
        //    var schem = Config.Instance.GetDbSchemInfo(this.ProviderElement);

        //    var table1Name = table1.GetTableName();
        //    var table1PrimaryKey = schem.GetPrimaryKey(table1Name);
        //    var table1PrimaryKeyProperty = DynamicAssignment.Instance.GetDictionary(table1)[table1PrimaryKey].PropertyInfo;

        //    var table2Name = table2.GetTableName();
        //    var table2PrimaryKey = schem.GetPrimaryKey(table2Name);
        //    var table2PrimaryKeyProperty = DynamicAssignment.Instance.GetDictionary(table2)[table2PrimaryKey].PropertyInfo;

        //    //创建中间关联表
        //    var relationTableName = string.Format("{0}_{1}_Relation", table1Name, table2Name);
        //    this.CreateTable(relationTableName, "id", "int", true);

        //    this.CreateFK(relationTableName, string.Format("{0}id", table1Name), this.GetDbType(table1PrimaryKeyProperty.PropertyType), table1Name, table1PrimaryKey);
        //    this.CreateFK(relationTableName, string.Format("{0}id", table2Name), this.GetDbType(table2PrimaryKeyProperty.PropertyType), table2Name, table2PrimaryKey);

        //}

        /// <summary>
        /// 关系类型
        /// </summary>
        [Obsolete]
        private enum RelationType { One2One, One2Many, Many2Many }

    }
}
